package com.superb.common.database.interceptor;

import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.superb.common.core.model.Result;
import com.superb.common.properties.SuperbCustomProperties;
import com.superb.common.security.feign.RemoteSecuritySystemService;
import com.superb.common.utils.SpringContextUtils;
import com.superb.common.utils.StringUtils;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import net.sf.jsqlparser.expression.Alias;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.select.FromItem;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Set;

/**
 * 索引检查插件
 *
 * @Author: ajie
 * @CreateTime: 2024-07-15 16:41
 */
@Intercepts({
        @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
@AllArgsConstructor
public class SuperbIndexCheckInterceptor implements InnerInterceptor {

    private SuperbCustomProperties properties;

    /**
     * 在查询之前获取执行sql
     *
     * @param executor      Executor(可能是代理对象)
     * @param ms            MappedStatement
     * @param parameter     parameter
     * @param rowBounds     rowBounds
     * @param resultHandler resultHandler
     * @param boundSql      boundSql
     * @return
     * @throws SQLException
     */
    @Override
    @SneakyThrows
    public boolean willDoQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        // 获取当前执行环境
        String profile = SpringContextUtils.getActiveProfile();
        RemoteSecuritySystemService securitySystemService = SpringContextUtils.getBean(RemoteSecuritySystemService.class);
        if ("prod".equals(profile)) {
            return true;
        }
        // 获取select操作集合
        Select selectStatement = (Select) CCJSqlParserUtil.parse(boundSql.getSql());
        // 获取select执行器
        PlainSelect select = selectStatement.getPlainSelect();
        // 获取主表名
        FromItem fromItem = select.getFromItem();
        String table = fromItem.toString();
        Alias alias = fromItem.getAlias();
        if (alias != null) {
            table = table.substring(0, table.indexOf(alias.toString()));
        }
        if (table.toLowerCase().contains("information_schema")) {
            return true;
        }
        // 排除租户和删除的表
        Set<String> tenantTable = properties.getIgnoreTenantTable();
        Set<String> delTable = properties.getIgnoreDelTable();
        // 排除租户拦截的--没有tenant_id的表 没有del字段的表
        if (delTable.contains(table) || tenantTable.contains(table)) {
            return true;
        }
        Set<String> checkColumns = properties.getIndexCheckColumns();
        for (String checkColumn : checkColumns) {
            if ("organ_id".equals(checkColumn)) {
                Result<Boolean> result = securitySystemService.getExistColumn(table, checkColumn);
                if (result.getCode() == 200 && result.isSuccess() && result.getResult()) {
                    Result<String> result2 = securitySystemService.getDatabaseIndex(table, checkColumn);
                    if (result2.getCode() == 200 && result2.isSuccess()) {
                        String index = result2.getResult();
                        if (StringUtils.isBlank(index)) {
                            throw new SQLException("数据表[" + table + "]公共字段[" + checkColumn + "]未设置索引");
                        }
                    }
                }
            } else {
                Result<String> result = securitySystemService.getDatabaseIndex(table, checkColumn);
                if (result.getCode() == 200 && result.isSuccess()) {
                    String index = result.getResult();
                    if (StringUtils.isBlank(index)) {
                        throw new SQLException("数据表[" + table + "]公共字段[" + checkColumn + "]未设置索引");
                    }
                }
            }
        }
        return true;
    }

}
